import datetime
from django.core.exceptions import ValidationError



class IntegerField:
    def __init__(self, required=False, min_value=None, max_value=None):
        self.required = required
        self.min_value = min_value
        self.max_value = max_value

    def validate(self, value):
        if self.required and not value:
            raise ValueError("该字段是必填的")
        if self.min_value and value < self.min_value:
            raise ValueError(f"值必须大于或等于{self.min_value}")
        if self.max_value and value > self.max_value:
            raise ValueError(f"值必须小于或等于{self.max_value}")
        return int(value)


class BooleanField:
    def __init__(self, required=False):
        self.required = required

    def validate(self, value, exception_t="未知"):
        if self.required and value not in [True, False]:
            raise ValueError(f"{exception_t}字段必须是一个布尔值")
        return bool(value)


class EmailField:
    def __init__(self, required=False):
        self.required = required

    def validate(self, value):
        if self.required and not value:
            raise ValueError("该字段是必填的")
        return value


class DateField:
    def validate(self):
        # 只提取日期部分
        current_date = datetime.datetime.now().date()
        # 将日期转换为字符串
        return current_date.strftime("%Y-%m-%d")


class UrlField:
    def __init__(self, required=False):
        self.required = required

    def validate(self, value):
        if self.required and not value:
            raise ValueError("该字段是必填的")
        if not value.startswith("http://") and not value.startswith("https://"):
            raise ValueError("无效的URL格式，请使用http://或https://")
        return value


from exts import BlogMongodb, all_logger
from typing import Any, Type


class Field:
    """字段基类，提供基础验证功能"""
    def __init__(self, required=False, default=None,log_default="Field检验基础段,请注意,一般情况下出现该段验证只能用于当前值是否存在,不推荐使用,如需要使用请修改log_Field" ):
        self.required = required
        self.default = default
        self.log_default = log_default

    def validate(self, value: Any, field_name: str) -> Any:
        """基础验证逻辑"""
        all_logger.warning(self.log_default)
        if value is None:
            if self.required:
                raise ValueError(f"{field_name}即value字段是必填字段,请添加validate的必选参数")
            return None
        return value


class StringField(Field):
    """字符串字段验证器"""

    def __init__(self, min_length=None, max_length=None, **kwargs , ):
        super().__init__(**kwargs, log_default="StringField检验段执行检验")
        self.min = min_length
        self.max = max_length

    def validate(self, value: str, field_name : str = "字符串字段") -> str:
        if value is None and self.required :
                raise ValueError(f"{field_name}即value字段是必填字段,请添加validate的必选参数")
        if value and not isinstance(value, str):
            raise ValidationError(f"{field_name} 必须是字符串类型")
        if self.min and len(value) < self.min:
            raise ValidationError(f"{field_name} 长度不能小于 {self.min}")
        if self.max and len(value) > self.max:
            raise ValidationError(f"{field_name} 长度不能超过 {self.max}")
        return value

class AutherField(Field):
    def __init__(self,  **kwargs):
        super().__init__(**kwargs , log_default="AutherField检验段执行检验")
        self.max_elements = max_elements

class TextField(StringField):
    """长文本字段（继承自StringField，自动设置最小长度）"""

    def __init__(self, min_length=200, **kwargs):
        super().__init__(min_length=min_length, **kwargs)


class SlugField(StringField):
    """URL友好标识符字段"""

    def validate(self, value: str, field_name: str) -> str:
        value = super().validate(value, field_name)
        if value:
            # 移除特殊字符并转换为小写
            cleaned = value.strip().lower().replace(" ", "-")
            cleaned = "".join(c for c in cleaned if c.isalnum() or c == "-")
            if len(cleaned) < 3:
                raise ValidationError(f"{field_name} 无效的标识符格式")
            return cleaned
        return value


class URLField(StringField):
    """URL验证字段"""

    def validate(self, value: str, field_name: str) -> str:
        value = super().validate(value, field_name)
        if value:
            # 简单URL格式验证
            if not value.startswith(("http://", "https://")):
                raise ValidationError(f"{field_name} 需要有效的URL地址")
            if len(value) > 2048:
                raise ValidationError(f"{field_name} URL长度超过限制")
        return value


class ReferenceField(Field):
    """引用其他集合文档的字段"""

    def __init__(self, reference_collection: str, **kwargs):
        super().__init__(**kwargs)
        self.collection = reference_collection

    def validate(self, value: str, field_name: str) -> str:
        value = super().validate(value, field_name)
        if value:
            # 检查引用的文档是否存在
            from exts import mongo
            if not mongo.db[self.collection].find_one({"_id": value}):
                raise ValidationError(f"{field_name} 引用的文档不存在")
        return value


class ListField(Field):
    """列表类型字段"""

    def __init__(self, field_type: Type[Field], max_elements=None, **kwargs):
        super().__init__(**kwargs)
        self.field_type = field_type
        self.max_elements = max_elements

    def validate(self, value: list, field_name: str) -> list:
        value = super().validate(value, field_name) or []
        # 验证每个列表元素
        validated = []
        for item in value:
            try:
                validated.append(self.field_type().validate(item, field_name))
            except ValidationError as e:
                raise ValidationError(f"{field_name} 列表项无效: {str(e)}")
        # 验证最大数量限制
        if self.max_elements and len(validated) > self.max_elements:
            raise ValidationError(f"{field_name} 最多包含 {self.max_elements} 个元素")
        return validated


class BlogModel:
    """博客数据模型"""

    def __init__(
            self,
            title: str,
            author: str,
            content: str,
            category: str,
            tags: list,
            status: str = "draft",
            slug: str = None,
            **kwargs
    ):
        """
        参数说明：
        - title: 博客标题 (5-120字符)
        - author: 作者ID (引用用户集合)
        - content: 博客内容 (至少200字符)
        - category: 分类 (技术/生活/公告/资源)
        - tags: 标签列表 (最多8个标签)
        - status: 状态 (草稿/已发布/归档)
        - slug: URL友好标识符 (自动生成)
        """
        try:
            # 核心元数据验证
            self.title = StringField(min_length=5, max_length=120, required=True).validate(title, "title")
            self.author = ReferenceField(reference_collection="users", required=True).validate(author, "author")
            self.slug = SlugField(required=True).validate(slug or title, "slug")

            # 内容验证
            self.content = TextField(min_length=200, required=True).validate(content, "content")
            self.category = StringField(
                allowed_values=["技术", "生活", "公告", "资源"],
                required=True
            ).validate(category, "category")

            # 标签系统验证
            self.tags = ListField(
                field_type=StringField(max_length=20),
                max_elements=8
            ).validate(tags, "tags")

            # 状态管理
            self.status = StringField(
                allowed_values=["draft", "published", "archived"],
                required=True
            ).validate(status, "status")

            # 自动生成字段
            self.created_at = datetime.now()
            self.updated_at = datetime.now()

        except ValidationError as e:
            all_logger.error(f"博客验证失败: {str(e)}")
            raise Exception("博客验证失败")

    # 其他方法保持不变...


from datetime import datetime, timezone
from dateutil.parser import parse  # 需要安装python-dateutil包


class DateTimeField(Field):
    """
    日期时间字段验证器

    参数：
    - auto_now: 是否在每次保存时自动设置为当前时间（常用于最后修改时间）
    - auto_now_add: 是否在创建时自动设置为当前时间（常用于创建时间）
    - timezone_aware: 是否强制使用时区信息（默认True）

    功能：
    - 自动转换常见时间格式字符串为datetime对象
    - 处理时区转换（默认转换为UTC时间）
    - 支持自动时间戳功能
    """

    def __init__(self, auto_now=False, auto_now_add=False, timezone_aware=True, **kwargs):
        super().__init__(**kwargs)
        self.auto_now = auto_now
        self.auto_now_add = auto_now_add
        self.timezone_aware = timezone_aware

        # 参数冲突检测
        if self.auto_now and self.auto_now_add:
            raise ValueError("不能同时设置auto_now和auto_now_add")

    def validate(self, value: Any, field_name: str) -> datetime:
        # 处理自动时间逻辑
        if self.auto_now_add and value is None:
            return self._get_current_time()
        if self.auto_now:
            return self._get_current_time()

        # 基础验证
        value = super().validate(value, field_name)

        # 转换逻辑
        try:
            dt = self._convert_to_datetime(value)
        except Exception as e:
            raise ValidationError(f"{field_name} 时间格式无效: {str(e)}")

        # 时区处理
        return self._ensure_timezone(dt)

    def _convert_to_datetime(self, value: Any) -> datetime:
        """将输入转换为datetime对象"""
        if isinstance(value, datetime):
            return value
        elif isinstance(value, (int, float)):
            return datetime.fromtimestamp(value, tz=timezone.utc)
        elif isinstance(value, str):
            try:
                return parse(value)  # 使用dateutil解析复杂格式
            except Exception:
                # 尝试ISO 8601格式
                return datetime.fromisoformat(value)
        else:
            raise TypeError("不支持的日期时间格式")

    def _ensure_timezone(self, dt: datetime) -> datetime:
        """确保有时区信息"""
        if self.timezone_aware:
            if dt.tzinfo is None:
                return dt.replace(tzinfo=timezone.utc)
            return dt.astimezone(timezone.utc)  # 统一转换为UTC时间
        else:
            return dt.replace(tzinfo=None)

    def _get_current_time(self) -> datetime:
        """获取当前时间（根据时区设置）"""
        now = datetime.now(timezone.utc) if self.timezone_aware else datetime.now()
        return now


# 在BlogModel中的使用示例
class BlogModel:
    def __init__(self):
        # 创建时间（仅在初始化时自动设置）
        self.created_at = DateTimeField(
            auto_now_add=True,
            timezone_aware=True,
            required=True
        ).validate(None, "created_at")

        # 更新时间（每次保存时自动更新）
        self.updated_at = DateTimeField(
            auto_now=True,
            timezone_aware=True,
            required=True
        ).validate(None, "updated_at")